//
// Created by Administrator on 2025/9/15.
//

#include "sdcard.h"
#include "FreeRTOS.h"
#include "semphr.h"
#include "ff.h"

#include "delay.h"

SD_HandleTypeDef g_sd_handle;
HAL_SD_CardInfoTypeDef g_sd_card_info;
#ifdef INC_FREERTOS_H
xSemaphoreHandle sdcard_rw_sem=NULL;
#else
    static volatile bool sdcard_tx_flag=false;
    static volatile bool sdcard_rx_flag=false;
#endif

uint32_t get_sdio_clk_freq(void)
{
    uint32_t sdio_clock_freq=0;
    uint32_t pll_q=0;
    uint32_t pll_m=0;
    uint32_t pll_n=0;
    uint32_t pll_source_clk=0;

    pll_q=(RCC->PLLCFGR&RCC_PLLCFGR_PLLQ)>>RCC_PLLCFGR_PLLQ_Pos;
    pll_m=(RCC->PLLCFGR&RCC_PLLCFGR_PLLM)>>RCC_PLLCFGR_PLLM_Pos;
    pll_n=(RCC->PLLCFGR&RCC_PLLCFGR_PLLN)>>RCC_PLLCFGR_PLLN_Pos;

    if ((RCC->PLLCFGR&RCC_PLLCFGR_PLLSRC)==RCC_PLLSOURCE_HSE)
        pll_source_clk=HSE_VALUE;
    else
        pll_source_clk=HSI_VALUE;

    sdio_clock_freq=(uint32_t)((float)pll_source_clk/pll_m*pll_n/pll_q);
    return sdio_clock_freq;
}

uint8_t sdcard_init(void)
{
    uint8_t SD_Error;

    /* 初始化时的时钟不能大于400KHZ */
    g_sd_handle.Instance = SDIO;
    g_sd_handle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;                       /* 上升沿 */
    g_sd_handle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;                  /* 不使用bypass模式，直接用HCLK进行分频得到SDIO_CK */
    g_sd_handle.Init.BusWide = SDIO_BUS_WIDE_1B;                               /* 1位数据线 */
    g_sd_handle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; /* 关闭硬件流控 */
    g_sd_handle.Init.ClockDiv = 6;                           /* SDIO initial clock must be <= 400KHz */

    SD_Error = HAL_SD_Init(&g_sd_handle);
    if (SD_Error != HAL_OK)
    {
        return 1;
    }

    HAL_SD_GetCardInfo(&g_sd_handle, &g_sd_card_info);                  /* 获取SD卡信息 */

    SD_Error = HAL_SD_ConfigWideBusOperation(&g_sd_handle, SDIO_BUS_WIDE_4B);  /* 使能4bit宽总线模式 */
    if (SD_Error != HAL_OK)
    {
        return 2;
    }
#ifdef INC_FREERTOS_H
    if (sdcard_rw_sem==NULL)
    {
        sdcard_rw_sem=xSemaphoreCreateBinary();
        if (sdcard_rw_sem==NULL)
            return 3;
    }
#endif

    return 0;
}

uint8_t sdcard_get_card_info(HAL_SD_CardInfoTypeDef *cardinfo)
{
    uint8_t sta;
    sta = HAL_SD_GetCardInfo(&g_sd_handle, cardinfo);
    return sta;
}

uint8_t sdcard_get_card_sta(void)
{
    uint8_t sta = HAL_SD_GetCardState(&g_sd_handle);
    return sta;
}

uint8_t sdcard_read(uint8_t *buf,uint32_t saddr, uint32_t len)
{
    uint8_t sta;

    sta=HAL_SD_ReadBlocks(&g_sd_handle,buf,saddr,len,HAL_MAX_DELAY);

    return sta;
}

uint8_t sdcard_read_dma(uint8_t *buf,uint32_t saddr, uint32_t len)
{
    uint32_t timeout=uwTick+1000;

    if (HAL_SD_ReadBlocks_DMA(&g_sd_handle,buf,saddr,len)!=HAL_OK)
        return HAL_ERROR;

#ifdef INC_FREERTOS_H
    if (xSemaphoreTake(sdcard_rw_sem,pdMS_TO_TICKS(FF_FS_TIMEOUT))!=pdTRUE)
    {
        return HAL_ERROR;
    }
    else
    {
        uint32_t tickstart=xTaskGetTickCount();
        while (HAL_SD_GetCardState(&g_sd_handle)!=HAL_SD_CARD_TRANSFER)
        {
            if (xTaskGetTickCount()-tickstart>pdMS_TO_TICKS(FF_FS_TIMEOUT))
            {
                return HAL_TIMEOUT;
            }
            vTaskDelay(1);
        }
    }
    return HAL_OK;
#else
    sdcard_rx_flag=false;
    while (sdcard_rx_flag ==false&&uwTick<timeout)
    {
        __NOP();
    }
    if (sdcard_rx_flag ==false)
    {
        return HAL_ERROR;
    }
    else
    {
        sdcard_rx_flag=false;
        timeout=uwTick+1000;
        while (uwTick<timeout)
        {
            if (HAL_SD_GetCardState(&g_sd_handle)==HAL_SD_CARD_TRANSFER)
            {
                return HAL_OK;
            }
        }
    }
    return HAL_ERROR;
#endif
}

uint8_t sdcard_write(uint8_t *buf,uint32_t saddr, uint32_t len)
{
    uint8_t sta;
    sta=HAL_SD_WriteBlocks_DMA(&g_sd_handle,buf,saddr,len);
    return sta;
}

uint8_t sdcard_write_dma(uint8_t *buf,uint32_t saddr, uint32_t len)
{
    uint32_t timeout=uwTick+1000;

    if (HAL_SD_WriteBlocks_DMA(&g_sd_handle,buf,saddr,len)!=HAL_OK)
        return HAL_ERROR;
#ifdef INC_FREERTOS_H
    if (xSemaphoreTake(sdcard_rw_sem,pdMS_TO_TICKS(FF_FS_TIMEOUT))!=pdTRUE)
    {
        return HAL_ERROR;
    }
    else
    {
        uint32_t tickstart=xTaskGetTickCount();
        while (HAL_SD_GetCardState(&g_sd_handle)!=HAL_SD_CARD_TRANSFER)
        {
            if (xTaskGetTickCount()-tickstart>pdMS_TO_TICKS(FF_FS_TIMEOUT))
            {
                return HAL_TIMEOUT;
            }
            vTaskDelay(1);
        }
    }
    return  HAL_OK;
#else
    sdcard_tx_flag=false;
    while (sdcard_tx_flag ==false&&uwTick<timeout)
    {
        __NOP();
    }
    if (sdcard_tx_flag ==false)
    {
        return HAL_ERROR;
    }
    else
    {
        sdcard_tx_flag=false;
        timeout=uwTick+1000;
        while (uwTick<timeout)
        {
            if (HAL_SD_GetCardState(&g_sd_handle)==HAL_SD_CARD_TRANSFER)
            {
                return HAL_OK;
            }
        }
    }
    return HAL_ERROR;
#endif

}



volatile bool sdcard_get_rx_flag(void)
{
#ifdef INC_FREERTOS_H
    __NOP();
#else
    return sdcard_rx_flag;
#endif

}
volatile bool sdcard_get_tx_flag(void)
{
#ifdef INC_FREERTOS_H
    __NOP();
#else
    return sdcard_tx_flag;
#endif
}

void sdcard_set_tx_flag(const bool flag)
{
#ifdef INC_FREERTOS_H
    __NOP();
#else
    sdcard_tx_flag=flag;
#endif

}

void sdcard_set_rx_flag(const bool flag)
{
#ifdef INC_FREERTOS_H
    __NOP();
#else
    sdcard_rx_flag=flag;
#endif
}

void BSP_SD_DMA_READ_CB(void)
{
#ifdef INC_FREERTOS_H
    BaseType_t pxHigherPriorityTaskWoken;
    xSemaphoreGiveFromISR(sdcard_rw_sem,&pxHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
#else
    sdcard_rx_flag=true;
#endif

}

void BSP_SD_DMA_WRITE_CB(void)
{
#ifdef INC_FREERTOS_H
    BaseType_t pxHigherPriorityTaskWoken;
    xSemaphoreGiveFromISR(sdcard_rw_sem,&pxHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
#else
    sdcard_tx_flag=true;
#endif

}

uint8_t sdcard_test(void)
{
    uint8_t result;
    HAL_SD_CardInfoTypeDef card_info;
    static uint8_t test_data[512];
    static uint8_t read_data[512];
    uint32_t i;

    // 初始化SD卡
    printf("正在初始化SD卡...\r\n");
    result = sdcard_init();
    if (result != 0) {
        printf("SD卡初始化失败，错误代码: %d\r\n", result);
        return result;
    }
    printf("SD卡初始化成功\r\n");

    // 获取SD卡信息
    printf("正在获取SD卡信息...\r\n");
    result = sdcard_get_card_info(&card_info);
    if (result != HAL_OK) {
        printf("获取SD卡信息失败\r\n");
        return 10 + result;
    }

    // 打印SD卡信息
    printf("SD卡类型: ");
    switch (card_info.CardType) {
        case CARD_SDSC:
            printf("SDSC\r\n");
            break;
        case CARD_SDHC_SDXC:
            printf("SDHC/SDXC\r\n");
            break;
        case CARD_SECURED:
            printf("SECURED\r\n");
            break;
        default:
            printf("未知类型\r\n");
            break;
    }
    printf("卡容量: %lu 扇区\r\n", card_info.LogBlockNbr);
    printf("扇区大小: %lu 字节\r\n", card_info.LogBlockSize);

    // 测试SD卡状态
    printf("检查SD卡状态...\r\n");
    uint8_t card_state = sdcard_get_card_sta();
    if (card_state != HAL_SD_CARD_TRANSFER && card_state != HAL_SD_CARD_READY) {
        printf("SD卡状态异常: %d\r\n", card_state);
        return 20;
    }
    printf("SD卡状态正常\r\n");

    // 准备测试数据
    for (i = 0; i < 512; i++) {
        test_data[i] = i % 256;
    }

    // 写入测试数据到第一个扇区
    printf("正在写入测试数据到扇区1...\r\n");
    result = sdcard_write(test_data, 1, 1);
    if (result != HAL_OK) {
        printf("写入数据失败，错误代码: %d\r\n", result);
        return 30 + result;
    }
    printf("数据写入成功\r\n");

    // 读取刚刚写入的数据
    printf("正在从扇区1读取数据...\r\n");
    result = sdcard_read(read_data, 1, 1);
    if (result != HAL_OK) {
        printf("读取数据失败，错误代码: %d\r\n", result);
        return 40 + result;
    }
    printf("数据读取成功\r\n");

    // 验证数据
    printf("正在验证数据...\r\n");
    for (i = 0; i < 512; i++) {
        if (test_data[i] != read_data[i]) {
            printf("数据验证失败，位置: %lu, 写入值: %d, 读取值: %d\r\n",
                   i, test_data[i], read_data[i]);
            return 50;
        }
    }
    printf("数据验证成功\r\n");

    printf("SD卡测试完成，所有测试项目通过\r\n");
    return 0; // 测试成功
}

